home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 (Walnut Creek) / Aminet - June 1993 [Walnut Creek].iso / usenet / sources / volume2 / aplictns / flowtrof.1 < prev    next >
Text File  |  1988-11-18  |  28KB  |  970 lines

  1. Path: xanth!mcnc!rutgers!mit-eddie!ll-xn!adelie!infinet!ulowell!page
  2. From: page@swan.ulowell.edu (Bob Page)
  3. Newsgroups: comp.sources.amiga
  4. Subject: v02i062:  flow2troff - convert flow files to troff input
  5. Message-ID: <10257@swan.ulowell.edu>
  6. Date: 18 Nov 88 03:42:56 GMT
  7. Organization: University of Lowell, Computer Science Dept.
  8. Lines: 959
  9. Approved: page@swan.ulowell.edu
  10.  
  11. Submitted-by: barrett@cs.jhu.edu (Dan Barrett)
  12. Posting-number: Volume 2, Issue 62
  13. Archive-name: applications/flow2troff.1
  14.  
  15. I have had numerous requests for this program since I announced it on
  16. USENET.  The program converts "Flow" files (from the "Flow" idea
  17. processor, by New Horizons Software) into UNIX "troff" files.  These
  18. files can then be printed on any Troff-compatible laser printer.
  19.  
  20. #    This is a shell archive.
  21. #    Remove everything above and including the cut line.
  22. #    Then run the rest of the file through sh.
  23. #----cut here-----cut here-----cut here-----cut here----#
  24. #!/bin/sh
  25. # shar:    Shell Archiver
  26. #    Run the following text with /bin/sh to create:
  27. #    Flow2Troff.c
  28. #    Flow2Troff.DOC
  29. #    Makefile
  30. #    Makefile.unix
  31. #    getopt.h
  32. #    sample.uu
  33. #    BUGS
  34. #    FIXES
  35. # This archive created: Thu Nov 17 22:36:08 1988
  36. cat << \SHAR_EOF > Flow2Troff.c
  37. /**********************************************************************
  38. * FLOW2TROFF:    Translate a "Flow" file into troff code.
  39. *        Daniel J. Barrett, 1988.  barrett@cs.jhu.edu (ARPAnet).
  40. *        PUBLIC DOMAIN.
  41. *
  42. * Usage:    Flow2Troff [options] Flow_file [Troff_File]
  43. *
  44. * Options:    See *usage_string[].
  45. *
  46. * Compiling:    (MANX Aztec C, 16-bit integers)
  47. *        (You also need a version of "getopt()".)
  48. *        cc Flow2Troff.c
  49. *        ln Flow2Troff.o -lc
  50. **********************************************************************/
  51.     
  52. #include <stdio.h>
  53. #ifndef UNIX
  54. #include <getopt.h>            /* I assume that UNIX/ULTRIX has   */
  55. #endif                    /* a built-in getopt() function.   */
  56.     
  57. #define FILE_END        -2    /* My own error flag.              */
  58. #define NUM_HEADER_BYTES    42L    /* How many header bytes to skip.  */
  59.  
  60. #define EQUAL        !strcmp        /* 2 useful functions.             */
  61. #define EXISTS(f)    !access(f,0)
  62.     
  63. #define UNDERLINE    1        /* The 5th byte of HSTL data has   */
  64. #define    BOLD        2        /* the font information.  Lowest 3 */
  65. #define ITALICS        4        /* bits are U, B, and I on/off.    */
  66.  
  67. #define    TRUE        1
  68. #define    FALSE        0
  69. #define    RIGHT        1
  70. #define LEFT        0
  71.     
  72. long indent;                /* Number of times to indent.      */
  73. int fontChange;                /* FALSE=plain, TRUE=bold/italics. */
  74. int printing;                /* Used with dFlag.  TRUE if the   */
  75.                     /* current line indent is less     */
  76.                     /* dFlag.                          */
  77. int quotes;
  78. int underlined;
  79.  
  80. extern char *optarg;            /* Necessary getopt() variables.   */
  81. extern int optind;
  82. char optstring[] = "htp:v:i:d:";
  83.  
  84. int pFlag, vFlag, iFlag, hFlag, dFlag, tFlag;
  85.  
  86. /**********************************************************************
  87. *            Usage information
  88. **********************************************************************/
  89.  
  90. static char *usage_string[] = {
  91. "",
  92. "[33mFlow2Troff V1.0[0m by Daniel J. Barrett.  PUBLIC DOMAIN.",
  93. "Convert from New Horizons Software \"Flow\" files to Troff files.",
  94. "",
  95. "Usage:        Flow2Troff [options] Flow_file [Troff_file]",
  96. "",
  97. "Options:    -p#    : Set troff point size (default 12)",
  98. "        -v#    : Set troff vertical spacing (default 13)",
  99. "        -i#    : Set indentation (default 3)",
  100. "        -d#    : Print only to specified depth (default all)",
  101. "        -h    : Permit hyphenation (default is none)",
  102. "        -t    : Title the outline with \"Flow_file\"",
  103. "",
  104. "If not specified, Troff_file is written on standard output.",
  105. "",
  106. NULL };
  107.  
  108.     
  109. /**********************************************************************
  110. *            M A I N    P R O G R A M
  111. **********************************************************************/
  112.  
  113. main(argc,argv)
  114. int argc; char *argv[];
  115. {
  116.     FILE *infile=NULL, *outfile=NULL;    /* infile = FLOW file.  */
  117.     char c;                    /* outfile = TROFF file */
  118.  
  119.     /* Set default values for our flags. */
  120.     pFlag=12, vFlag=13, iFlag=3, hFlag=FALSE, dFlag=0, tFlag=FALSE;
  121.  
  122.     /* Parse the command line, getting and setting all options. */
  123.     while ((c = getopt(argc, argv, optstring)) != EOF)
  124.         switch (c) {
  125.             case 'p':    pFlag = atoi(optarg);
  126.                     CheckPositive(pFlag, 'p', ">");
  127.                     break;
  128.             case 'v':    vFlag = atoi(optarg);
  129.                     CheckPositive(vFlag, 'v', ">");
  130.                     break;
  131.             case 'i':    iFlag = atoi(optarg);
  132.                     CheckPositive(iFlag, 'i', ">");
  133.                     break;
  134.             case 'd':    dFlag = atoi(optarg);
  135.                     CheckPositive(dFlag, 'd', ">=");
  136.                     break;
  137.             case 'h':    hFlag = TRUE;
  138.                     break;
  139.             case 't':    tFlag = TRUE;
  140.                     break;
  141.             case '?':    Usage();
  142.                     break;
  143.         }
  144.  
  145.     /* Open infile and outfile. */
  146.     if (!OpenTheFiles(argc, argv, optind, &infile, &outfile))
  147.         Cleanup(infile, outfile, "File opening failed... bye!");
  148.  
  149.     /* If infile is the wrong type, quit. */
  150.     if (NotFlowFile(infile, outfile))
  151.         Cleanup(infile, outfile, "Invalid input file... bye!");
  152.  
  153.     /* Skip the header bytes, convert to troff, and quit. */
  154.     SkipBytes(infile, outfile, NUM_HEADER_BYTES);
  155.     Flow2Troff(infile, outfile, argv[optind]);
  156.     Cleanup(infile, outfile, NULL);
  157. }
  158.  
  159.     
  160. /**********************************************************************
  161. *        Indentifying FLOW commands
  162. **********************************************************************/
  163.  
  164. Flow2Troff(infile, outfile, title)
  165. /* Continually read commands from the Flow file.  GetCommand() finds each
  166.  * TEXT, NEST, or HSTL command and stores it in "command".  Then Convert()
  167.  * processes that command and its data.  "title" is the name of the infile. */
  168. FILE *infile, *outfile;
  169. char *title;
  170. {
  171.     char command[5];
  172.     int error;
  173.  
  174.     indent = 0;            /* Initialize global variables. */
  175.     fontChange = FALSE;        /* No indent, plain font, and   */
  176.     printing = TRUE;        /* printing turned on.          */
  177.     underlined = FALSE;        /* Is current text underlined?  */
  178.     quotes = LEFT;            /* Print left or right quotes?  */
  179.     
  180.     TroffHeader(outfile, title);    /* Output mandatory troff header. */
  181.  
  182.     do {
  183.         if (GetCommand(infile, outfile, command) == FILE_END)
  184.             return(FILE_END);
  185.         error = Convert(infile, outfile, command);
  186.     } while (!error);
  187.  
  188.     return(error);
  189. }
  190.  
  191.     
  192. GetCommand(infile, outfile, command)
  193. /* Get the four-letter formatting command from infile. */
  194. FILE *infile, *outfile;
  195. char command[];
  196. {
  197.     int n=4;
  198.     char c;
  199.  
  200.     StupidHack(infile, outfile);        /* Yeccchh. */
  201.  
  202.     /* Read a four-character command, one byte at a time. */
  203.     while (n && ((c = getc(infile)) != EOF)) {
  204.         command[4-n] = c;
  205.         n--;
  206.     }
  207.  
  208.     /* Did we get the whole command? */
  209.     if (n)                /* We must have hit EOF...       */
  210.         return(FILE_END);    /* ... so complain.              */
  211.     else {
  212.         command[4] = '\0';    /* Terminate command with a null */
  213.         return(0);        /* so we can use it as a string. */
  214.     }
  215. }
  216.  
  217.     
  218. Convert(infile, outfile, command)
  219. /* Depending on what kind of command we have, run the appropriate 
  220.  * Flow --> Troff conversion routine. */
  221. FILE *infile, *outfile;
  222. char *command;
  223. {
  224.     if (EQUAL(command, "TEXT"))        /* Actual text. */
  225.         return(DumpText(infile, outfile));
  226.     else if (EQUAL(command, "NEST"))    /* Indentation data. */
  227.         return(Indent(infile, outfile));
  228.     else if (EQUAL(command, "HSTL"))    /* Text style change. */
  229.         return(ChangeStyle(infile, outfile));
  230.     else {                    /* Error! */
  231.         fprintf(stderr, "Error found in file!\n");
  232.         return(FILE_END);
  233.     }
  234. }
  235.  
  236.     
  237. /**********************************************************************
  238. *            The actual translation routines
  239. **********************************************************************/
  240.  
  241. TroffHeader(outfile, title)
  242. /* Output some mandatory Troff code into the outfile. */
  243. FILE *outfile;
  244. char *title;
  245. {
  246.     DefineUnderline(outfile);
  247.     fprintf(outfile, ".ps %d\n", pFlag);    /* Point size.           */
  248.     fprintf(outfile, ".vs %d\n", vFlag);    /* Vertical spacing.     */
  249.     if (!hFlag)
  250.         fprintf(outfile, ".nh\n");    /* No hyphenation.       */
  251.     fprintf(outfile, ".ad b\n");        /* Left & right justify. */
  252.  
  253.     /* If we have a title, print it.  Else, just print 5 newlines. */
  254.     if (tFlag)
  255.         fprintf(outfile, ".sp 5\n.ft B\n.ce 1\n%s\n.ft R\n.sp 3\n",
  256.             title);
  257.     else
  258.         fprintf(outfile, ".sp 5\n");
  259. }
  260.  
  261.     
  262. DefineUnderline(outfile)
  263. /* Define a troff "underline string" command, ".us".  This is from the
  264.  * NROFF/TROFF USER'S MANUAL, page 20,  in Volume 2 of THE UNIX PROGRAMMER'S
  265.  * MANUAL. */
  266. FILE *outfile;
  267. {
  268.     fprintf(outfile, ".de us\n\\\\$1\\l'|0\\(ul'\n..\n");
  269. }
  270.  
  271.     
  272. DumpText(infile, outfile)
  273. /* For a TEXT command, find the length of its data, and then output that
  274.  * data. */
  275. FILE *infile, *outfile;
  276. {
  277.     int i;
  278.     unsigned char len[4];
  279.     long textLength=0L;
  280.     char c;
  281.  
  282.     /* TEXT data is stored in a variable length field.  The first
  283.      * 4 bytes are a longword; they store the length of the text
  284.      * string immediately following. */
  285.  
  286.     /* Get length of text, in characters.  The length is stored as
  287.      * a 4-byte field.  We must convert this to a long. */
  288.  
  289.     for (i=0; i<4; i++)
  290.         len[i] = getc(infile);
  291.  
  292.     textLength = (long)     ((len[0] << 24)
  293.                 + (len[1] << 16)
  294.                 + (len[2] << 8 )
  295.                 +  len[3]);
  296.  
  297.     /* If we are printing (not indented past dFlag), print the text.
  298.      * If we were printing in an alternate font, return to plain.
  299.      * If we were not printing, just skip all the text data entirely. */
  300.  
  301.     if (printing) {
  302.         for (i=0; i<textLength; i++) {
  303.             c = getc(infile);
  304.             if (underlined && c == '"') {
  305.                 if (quotes == LEFT) {
  306.                     fprintf(outfile, "``");
  307.                     quotes = RIGHT;
  308.                 }
  309.                 else {
  310.                     fprintf(outfile, "''");
  311.                     quotes = LEFT;
  312.                 }
  313.             }
  314.             else
  315.                 putc(c, outfile);
  316.         }
  317.         if (underlined) {        /* Terminate underlining. */
  318.             putc('"', outfile);
  319.             underlined = FALSE;
  320.         }
  321.         fprintf(outfile, "\n");
  322.         if (fontChange) {
  323.             fprintf(outfile, ".ft R\n");
  324.             fontChange = FALSE;
  325.         }
  326.         fprintf(outfile, ".br\n");
  327.     }
  328.     else
  329.         SkipBytes(infile, outfile, textLength);
  330.  
  331.     return(0);
  332. }
  333.  
  334.     
  335. Indent(infile, outfile)
  336. /* Print the proper troff ".in" indenting information.  This algorithm
  337.  * is not as straightforward as I thought it would be. */
  338. FILE *infile, *outfile;
  339. {
  340.     long newIndent=0;        /* New indent value, to be read. */
  341.     long Abs();            /* Absolute value.               */
  342.     unsigned char temp[2];        /* Two bytes of newIndent value. */
  343.     char plusMinus;            /* Holds either a '+' or a '-'.  */
  344.     int i;
  345.  
  346.     /* NEST data is 6 bytes long.  The first four bytes are 0 0 0 2, and
  347.      * I don't know their meaning.  The last two bytes represent the
  348.      * absolute indentation from the left margin. */
  349.  
  350.     SkipBytes(infile, outfile, 4L);
  351.     for (i=0; i<2; i++) {
  352.         temp[i] = getc(infile);
  353.         if (temp[i] == EOF)
  354.            Cleanup(infile, outfile, "Bad indentation data.. bye!");
  355.     }
  356.     newIndent = (long)(temp[1] + (temp[0] << 8));  /* New indent value. */
  357.  
  358.     /* INDENTATION ALGORITHM.
  359.      *
  360.      * Assume we are currently printing.
  361.      *     If the -d flag is not specified, we simply do the indent.
  362.      *    Same deal if we DO have -d, but we're not indented past dFlag.
  363.      *    But if we used -d AND we indented too far, we turn off
  364.      *     printing.
  365.      *
  366.      * Alternatively, assume we are NOT currently printing.  We could
  367.      *  get here ONLY if the -d flag has been set.
  368.      *    If the new indent value is greater than or equal to the -d
  369.      *     value, then we do nothing... we still should not print.
  370.      *    Otherwise, the new indent value is less than the -d value.
  371.      *     Turn printing back on.
  372.      *     For all intents and purposes, we may now pretend that our
  373.      *      current indent value was the maximum printable:  dFlag-1.
  374.      *     If the newIndent value is ALSO dFlag-1, we do not need to
  375.      *      do any indents... just stay where we are.  Otherwise, do
  376.      *      an indent (which MUST be negative) backwards from dFlag.
  377.      *
  378.      * Simple, eh?                            */
  379.  
  380.     if (printing) {
  381.         if (dFlag==0 || (newIndent < dFlag)) {
  382.             plusMinus = ((newIndent - indent) >= 0)
  383.                   ? '+'
  384.                   : '-';
  385.             fprintf(outfile, ".in %c%ld\n", plusMinus, 
  386.                 Abs((newIndent-indent)*iFlag));
  387.         }
  388.         else
  389.             printing = FALSE;
  390.     }
  391.     else if (newIndent < dFlag) {
  392.         printing = TRUE;
  393.         if (newIndent != (dFlag-1))
  394.             fprintf(outfile, ".in -%ld\n",
  395.              Abs((newIndent-(dFlag-1))*iFlag));
  396.     }
  397.     indent = newIndent;        /* Keep the new indent value. */
  398.     return(0);
  399. }
  400.  
  401.     
  402. ChangeStyle(infile, outfile)
  403. /* Change to bold, italics, underline. Troff cannot do both bold & italics
  404.  * simultaneously, so bold takes precedence here.  Underlining is a real
  405.  * hack. */
  406. FILE *infile, *outfile;
  407. {
  408.     char style=0;
  409.  
  410.     /* HSTL data is 6 bytes.  The 5th byte contains style change info.
  411.      * The lowest bit is underline on/off, the next is bold on/off, and
  412.      * the third is italics on/off.  I don't know what the other 5 bytes
  413.      * stand for. */
  414.  
  415.     /* If we are printing, print the appropriate troff style change
  416.      * info.  Else, just skip the 6 bytes of HSTL data. */
  417.  
  418.     if (printing) {
  419.         SkipBytes(infile, outfile, 4L);
  420.         style = getc(infile);
  421.  
  422.         if (style & BOLD) {
  423.             fprintf(outfile, ".ft B\n");
  424.             fontChange = TRUE;
  425.         }
  426.         else if (style & ITALICS) {
  427.             fprintf(outfile, ".ft I\n");
  428.             fontChange = TRUE;
  429.         }
  430.         if (style & UNDERLINE) {
  431.             underlined = TRUE;
  432.             fprintf(outfile, ".us \"");   /* quote before text */
  433.         }
  434.         SkipBytes(infile, outfile, 1L);
  435.     }
  436.     else
  437.         SkipBytes(infile, outfile, 6L);
  438.  
  439.     return(0);
  440. }
  441.  
  442. /**********************************************************************
  443. *            File opening routines
  444. **********************************************************************/
  445.     
  446. OpenTheFiles(argc, argv, optind, infile, outfile)
  447. /* Open input and output files, return their pointers in infile and
  448.  * outfile.  If no outfile specified, use stdout. */
  449. int argc;
  450. char *argv[];
  451. int optind;
  452. FILE **infile, **outfile;
  453. {
  454.     int argsLeft = argc - optind;
  455.  
  456.     if (argsLeft == 2) {        /* infile & outfile were specified. */
  457.         if ((*infile = fopen(argv[optind], "r")) == NULL) {
  458.             perror(argv[optind]);
  459.             return(FALSE);
  460.         }
  461.         optind++;
  462.         if (DontOverwriteExistingFile(argv[optind]))
  463.             return(FALSE);
  464.         if ((*outfile = fopen(argv[optind], "w")) == NULL) {
  465.             perror(argv[optind]);
  466.             return(FALSE);
  467.         }
  468.     }
  469.     else if (argsLeft == 1) {    /* Only infile specified. */
  470.         if ((*infile = fopen(argv[optind], "r")) == NULL) {
  471.             perror(argv[optind]); 
  472.             return(FALSE);
  473.         }
  474.         *outfile = stdout;
  475.     }
  476.     else                     /* Bad syntax */
  477.         Usage();
  478. }
  479.  
  480.     
  481. DontOverwriteExistingFile(filename)
  482. /* If filename already exists, inform the user, who may choose to 
  483.  * continue or quit. */
  484. char *filename;
  485. {
  486.     static char *ex = "File \"%s\" already exists; overwrite it? (n/y): ";
  487.     if (!EXISTS(filename))
  488.         return(FALSE);
  489.     else {
  490.         fprintf(stderr, ex, filename);
  491.         if (getchar() != 'y')
  492.             return(TRUE);
  493.         else
  494.             return(FALSE);
  495.     }
  496. }
  497.  
  498.     
  499. NotFlowFile(infile, outfile)
  500. /* If file is not a FLOW file, return TRUE.  Otherwise, return FALSE.
  501.  * We assume that infile points to the beginning of the file. */
  502. FILE *infile, *outfile;
  503. {
  504.     int i;
  505.     unsigned char buf[5];
  506.  
  507.     /* Check if the file is a custom IFF "FORM" file. */
  508.  
  509.     for (i=0; i<4; i++) {
  510.         buf[i] = getc(infile);
  511.         if (buf[i] == EOF)
  512.             return(TRUE);
  513.     }
  514.     buf[4] = '\0';
  515.     if (strcmp(buf, "FORM")) {
  516.         fprintf(stderr, "Not an IFF FORM file.\n");
  517.         return(TRUE);
  518.     }
  519.  
  520.     /* Check if the type of the FORM file is "HEAD". */
  521.  
  522.     SkipBytes(infile, outfile, 4L);
  523.     for (i=0; i<4; i++) {
  524.         buf[i] = getc(infile);
  525.         if (buf[i] == EOF)
  526.             return(TRUE);
  527.     }
  528.     buf[4] = '\0';
  529.     if (strcmp(buf, "HEAD")) {
  530.         fprintf(stderr, "Infile is IFF FORM, but wrong type.\n");
  531.         return(TRUE);
  532.     }
  533.  
  534.     /* If we got here, then the file must be OK. */
  535.  
  536.     fseek(infile, 0L, 0);        /* Return to beginning of file. */
  537.     return(FALSE);
  538. }
  539.     
  540. /**********************************************************************
  541. *            Miscellaneous little routines    
  542. **********************************************************************/
  543.  
  544. SkipBytes(infile, outfile, n)
  545. /* Skip over the next n bytes in file pointed to by infile.
  546.  * If we reach EOF, quit. */
  547. FILE *infile, *outfile;
  548. long n;
  549. {
  550.     while (n && (getc(infile) != EOF))
  551.         n--;
  552.     if (n)
  553.         Cleanup(infile, outfile, "File ended before I was done!");
  554. }
  555.  
  556.     
  557. Usage()
  558. /* Print a program usage message, then exit. */
  559. {
  560.     char **str = usage_string;
  561.     while (*str)
  562.         fprintf(stderr, "%s\n", *(str++));
  563.     exit(5);
  564. }
  565.  
  566.     
  567. Cleanup(infile, outfile, s)
  568. /* Exit the program gracefully. */
  569. FILE *infile, *outfile;
  570. char *s;
  571. {
  572.     if (infile)
  573.         fclose(infile);
  574.     if (outfile)
  575.         fclose(outfile);
  576.     if (s)
  577.         fprintf(stderr, "%s\n", s);
  578.     exit(0);
  579. }
  580.  
  581.     
  582. StupidHack(infile, outfile)
  583. /* Sometimes, there is a zero immediately following TEXT data.  I
  584.  * have no idea why it is there.  Since it seems to contribute no
  585.  * information useful for troff, I just skip it. */
  586. FILE *infile, *outfile;
  587. {
  588.     char c;
  589.  
  590.     c = getc(infile);
  591.     if (c == EOF)
  592.         Cleanup(infile, outfile, NULL);
  593.     else if (c != 0)
  594.         ungetc(c, infile);
  595. }
  596.  
  597.     
  598. long Abs(x)
  599. /* Return the absolute value of x. */
  600. long x;
  601. {
  602.     return((x<0) ? -x : x);
  603. }
  604.  
  605.     
  606. CheckPositive(value, flag, sign)
  607. /* Print an error message if the value of the flag is out of range. */
  608. int value;
  609. char flag, *sign;
  610. {
  611.     static char *message = "ERROR: -%c value must be %s 0.\n";
  612.  
  613.     if ((EQUAL(sign, ">") && (value <= 0))
  614.     ||  (EQUAL(sign, ">=") && (value < 0)))
  615.         fprintf(stderr, message, flag, sign), exit(5);
  616. }
  617. SHAR_EOF
  618. cat << \SHAR_EOF > Flow2Troff.DOC
  619. **************************************************************************
  620. * Flow2Troff:    Convert from New Horizons Software "FLOW" files to
  621. *        UNIX "troff" files, suitable for printing on any
  622. *        troff-compatible laser printer.
  623. *
  624. * Author:    Daniel Barrett    (barrett@cs.jhu.edu)
  625. *        Department of Computer Science
  626. *        The Johns Hopkins University
  627. *        Baltimore, MD  21218
  628. *
  629. * Status:    Flow2Troff and Flow2Troff.c are in the PUBLIC DOMAIN.
  630. *        So is getopt.h, by "aklevin", to the best of my knowledge.
  631. *
  632. * Current version of Flow2Troff is 1.0.
  633. **************************************************************************
  634.  
  635. CONTENTS
  636. --------
  637.  
  638.     How to invoke Flow2Troff
  639.     Detailed description of the options
  640.     Printing the final product
  641.     Playing with bold, italics & underline styles
  642.     Compiling Flow2Troff
  643.  
  644.  
  645. How to invoke Flow2Troff
  646. ------------------------
  647.  
  648. If you just type "Flow2Troff", you'll get the following message:
  649.  
  650. Usage:        Flow2Troff [options] Flow_file [Troff_file]
  651.  
  652. Options:    -p#    : Set troff point size (default 12)
  653.         -v#    : Set troff vertical spacing (default 13)
  654.         -i#    : Set indentation (default 3)
  655.         -d#    : Print only to specified depth (default all)
  656.         -h    : Permit hyphenation (default is none)
  657.         -t    : Title the outline with "Flow_file"
  658.  
  659. Notes:
  660.     [options] refers to one or more of the listed options.
  661.     "Flow_File" is the Flow file used as input to the program.
  662.     "Troff_file" is the output file, containing troff code.
  663.  
  664.     If not specified, Troff_file is written on standard output.
  665.  
  666.  
  667. Detailed description of the options
  668. -----------------------------------
  669.  
  670.     Options may be given separately or combined, and in any order.  For
  671. options with arguments (all options except -h), you may separate the option
  672. >from its argument by a space, if you want.
  673.  
  674. The following two sets of options are exactly equivalent:
  675.  
  676.     Flow2Troff -p18 -d3 -h Flow_file
  677.  
  678.     Flow2Troff -hd3 -p 18 Flow_file
  679.  
  680.     Here is a brief chart of what Flow2Troff's options do.  It
  681. helps if you know troff, but you can still use the program without that
  682. knowledge.
  683.  
  684. Option        Troff Equivalent    Explanation
  685. -------------------------------------------------------------------------
  686. -p#, -p #    .ps #            Set your point size; how tall do
  687.                     you want your characters?
  688. -v#, -v #    .vs #            Vertical spacing; how much space
  689.                     between lines of text?
  690. -i#, -i #    .in +#            How many spaces is considered
  691.                     one "indent"?
  692. -d#, -d #    <none>            Print the outline only to the
  693.                     specified depth.  Try it a few
  694.                     times and you'll see what it
  695.                     does.
  696. -h        (removes        Allow long words to be separated by
  697.         ".nh")            a hyphen at the end of a line.
  698.                     Default: no hyphenation allowed.
  699. -t        .ce 1
  700.         .ft B            Give your outline a title.
  701.         Flow_file        The title is the name of the
  702.         .ft R            input Flow file.
  703.  
  704.  
  705. Playing with bold, italics, & underline styles
  706. ----------------------------------------------
  707.  
  708.     Flow allows you to have simultaneous bold, italics, and underline
  709. styles.  Troff allows either bold or italics, not both, and has no
  710. built-in ability for underlining.  Flow2Troff has to obey the limits of
  711. troff, by definition.
  712.     In Flow2Troff, you can have bold, italics, bold + underline, 
  713. italics + underline, or plain.  If you Flow_file has a heading with
  714. both bold and italics, then bold takes precedence.
  715.     Underlining is a real hack, but I don't know a better way
  716. to do it in Troff.
  717.  
  718.  
  719. Printing the Final Product
  720. --------------------------
  721.  
  722. (1)    Use FLOW to create an outline.  Save in "normal" file format.
  723. (2)    Flow2Troff [options] Flow_file Troff_file.
  724. (3)    Transfer Troff_file to a UNIX machine.
  725. (4)    On a UNIX system, print Troff_file with the program "troff".
  726.     Exact syntax varies from system to system.  You might want
  727.     to use the "-me" macro package (or similar) to introduce
  728.     page breaks; Flow2Troff DOES NOT CALCULATE PAGE BREAKS FOR YOU.
  729.  
  730. Compiling Flow2Troff
  731. --------------------
  732.  
  733.     Flow2Troff compiles & runs on both Amiga and 4.2BSD UNIX
  734. systems.  (I haven't tested it on other UNIX systems, but I see no
  735. reason that Flow2Troff wouldn't work.)
  736.  
  737. AMIGA:    I use MANX C V3.6.  To compile, use the supplied Makefile,
  738.     or type:
  739.  
  740.             cc Flow2Troff.c
  741.             ln Flow2Troff.o -lc
  742.  
  743.     I would guess that Flow2Troff compiles fine under Lattice C also.
  744.  
  745. UNIX:    Use the supplied Makefile.unix, or type:
  746.  
  747.             cc -DUNIX Flow2Troff.c -o Flow2Troff
  748. SHAR_EOF
  749. cat << \SHAR_EOF > Makefile
  750. # Makefile for Flow2Troff, Aztec C.
  751.  
  752. all:        Flow2Troff.o
  753.         ln +Q Flow2Troff.o -o Flow2Troff -lc
  754.  
  755. Flow2Troff.o:    getopt.h
  756. SHAR_EOF
  757. cat << \SHAR_EOF > Makefile.unix
  758. # Makefile for Flow2Troff, UNIX version
  759. # You must have a built-in getopt() function, since the supplied
  760. #  getopt.h doesn't work under all version of UNIX.
  761.  
  762. CFLAGS=-DUNIX
  763.  
  764. all:        Flow2Troff.o
  765.         cc Flow2Troff.o -o Flow2Troff
  766. SHAR_EOF
  767. cat << \SHAR_EOF > getopt.h
  768. /*  getopt.h - Get next option letter from argument vector.
  769.                v1.1  12-Dec-1987  aklevin
  770. */
  771.  
  772. #define GETOPT_H
  773.  
  774. #ifndef _STDIO_H
  775. #include <stdio.h>
  776. #endif
  777.  
  778. /*  optarg points to an option's argument (if any).
  779.     optind holds the index of the next argument vector element to parse.
  780.      Once all options have been parsed, points to the first non-option argument.
  781.      [If (optind > argc) then there are no more arguments].
  782.     opterr, if set to 0 will suppress getopt's error messages (default is 1).
  783.     optopt, while not usually documented, is used here to return the actual
  784.      option character found, even when getopt itself returns '?'.
  785. */
  786. char *optarg;
  787. int optind=1, opterr=1, optopt;
  788.  
  789. int
  790. getopt(argc, argv, optstring)
  791. int argc;
  792. char *argv[], *optstring;
  793. {
  794.  
  795. int any_more, i, result;
  796. static int opthold, optsub=1;
  797.  
  798. /*  Reset optarg upon entry  */
  799. *optarg = '\0';
  800.  
  801. /*  Reset optsub if caller has changed optind.  */
  802. if (optind != opthold) optsub = 1;
  803.  
  804. /*  Look at each element of the argument vector still unparsed.  */
  805. for ( ; optind < argc; optind++) {
  806.     /*  Done if a non-option argument or single dash is reached.
  807.         However, don't skip over said argument.  */
  808.     if (argv[optind][0] != '-' || argv[optind][1] == '\0') break;
  809.  
  810.     /*  Got an option.  */
  811.  
  812.     /*  Done if "--" is reached.  Skip over it, too.  */
  813.     if (argv[optind][1] == '-') {
  814.         optind++;
  815.         break;
  816.     }
  817.  
  818.     /*  Look at each character in optstring.  */
  819.     for (i=0; i < strlen(optstring); i++) {
  820.         if ( (optopt = argv[optind][optsub]) != optstring[i]) continue;
  821.  
  822.         /*  Got a match.  */
  823.  
  824.         /*  Are there any more chars in this option?  e.g. `-abc'  */
  825.         any_more = strlen(argv[optind])-optsub-1;
  826.  
  827.         /*  Does this option require an argument?  */
  828.         if (optstring[i+1] == ':') {
  829.  
  830.             /*  Yes.  If this is the last argument, complain.  */
  831.             if (optind == argc-1 && !any_more) {
  832.                 if (opterr) fprintf(stderr, "%s: `-%c' option requires an argument.\n", argv[0], optopt);
  833.                 optind++;
  834.                 result='?';
  835.                 goto leave;
  836.             } /* end if (opt */
  837.  
  838.             /*  Qualifier is either rest of this argument (if any)
  839.                 or next argument.  */
  840.             else {
  841.                 if (!any_more) optarg = argv[++optind];
  842.                 else optarg = &argv[optind][optsub+1];
  843.                 optind++;
  844.                 optsub=1;
  845.             } /* end else */
  846.         } /* end if (opt */
  847.         else {
  848.             /*  No argument; just adjust indices.  */
  849.             /*  Advance to next argument.  */
  850.             if (!any_more) {
  851.                 optind++;
  852.                 optsub=1;
  853.             } /* end if (! */
  854.             /*  Advance to next character.  */
  855.             else optsub++;
  856.         } /* end else */
  857.         result=optopt;
  858.         goto leave;
  859.     } /* end for (i=0 */
  860. if (opterr) fprintf(stderr, "%s: Unrecognized option `-%c'.\n", argv[0], optopt);
  861. if (strlen(argv[optind])-optsub-1) optsub++;
  862. else {
  863.     optind++;
  864.     optsub=1;
  865. }
  866. result='?';
  867. goto leave;
  868. } /* end for ( ; */
  869. result=EOF;
  870. leave:
  871.     opthold = optind;
  872.     return(result);
  873. } /* end getopt() */
  874.  
  875. SHAR_EOF
  876. cat << \SHAR_EOF > sample.uu
  877.  
  878. begin 644 sample.flow
  879. M1D]230```?Y(14%$4$%'10````I@0@P&!!4`````3U!44P````0%````5$58Y
  880. M5````!-4:&ES(&ES(&%N(&]U=&QI;F4N`$Y%4U0````"``%415A4````%TD@Z
  881. M86T@;F]W(&EN9&5N=&5D(&]N8V4N`%1%6%0````K4W1I;&P@:6YD96YT960@C
  882. M;VYC92P@8G5T($D@:&%V92!S=6)H96%D:6YG<P!.15-4`````@`"5$585```9
  883. M``Y);F1E;G1E9"!T=VEC94Y%4U0````"``-415A4````%4EN9&5N=&5D('1HU
  884. M<F5E('1I;65S(0!.15-4`````@`"5$585````!A"86-K('1O(")I;F1E;G1E7
  885. M9"!T=VEC92).15-4`````@``5$585````!U!;&P@=&AE('=A>2!B86-K('1O_
  886. M('1H92!L969T+@!(4U1,`````@(D5$585````!54:&ES(&ES(&EN(&)O;&0@#
  887. M9F%C92X`2%-43`````($)%1%6%0````35&AI<R!I<R!I;B!I=&%L:6-S+@!($
  888. M4U1,`````@$D5$585````!-4:&ES(&ES('5N9&5R;&EN960N`$A35$P````"[
  889. M`R1415A4````$D)O;&0@*R!U;F1E<FQI;F5D+DA35$P````"!21415A4````M
  890. 7%4ET86QI8W,@*R!U;F1E<FQI;F5D+@!I*
  891. ``
  892. end
  893. size 518
  894. SHAR_EOF
  895. cat << \SHAR_EOF > BUGS
  896. BUGS in V1.0:
  897.  
  898. (1)    The command for generating troff underlining, ".us", is not so great.
  899.     ".us" uses double quotes as a delimiter character.  So, any double
  900.     quotes in the middle of an underlined string must be converted to
  901.     a pair of single quotes.
  902.  
  903.     The bug is that if you have an ODD NUMBER of double quote in an
  904.     underlined string, the quotes will face the wrong way.  Example:  5"
  905.     will come out as 5``.
  906.  
  907.     This is because my algorithm assumes you have PAIRS of double
  908.     quotes surrounding strings.  It cannot handle an isolated
  909.     double quote correctly.
  910. SHAR_EOF
  911. cat << \SHAR_EOF > FIXES
  912. FIXES (V1.0):
  913.  
  914. (1)    Wrote the file Flow2Troff.doc for documentation.
  915.  
  916. (2)    Changed puts() to fprintf(stderr) in Usage(), so user still
  917.     gets an error message even if he redirects output.
  918.  
  919. (3)    Added support for FLOW underlining.  Since troff cannot do
  920.     underlining without a lot of work, I hacked in a ".us"
  921.     Troff macro.
  922.  
  923. FIXES (V0.95):
  924.  
  925. (1)    -t option added; generate a centered, bold-faced title on the
  926.     printed outline.  The title is the name of the Flow input file.
  927.  
  928. (2)    Changed SkipBytes().  Instead of returning a fail value, it now
  929.     simply quits the program.
  930.  
  931. (3)    Commented the source code extensively.
  932.  
  933. (4)    Added support for FLOW underlining.  Since troff cannot do
  934.     underlining without a lot of work, I substitute italics by
  935.     default.  This can be overridden by the -u flag.
  936.  
  937. FIXES (V0.9):
  938.  
  939. (1)    -d option now works correctly.  It used to print to level d+1 instead
  940.     of level d.
  941.  
  942. (2)    New Indent() algorithm, with new variable "printing", that eliminates
  943.     spurious ".in" troff commands.  This meant modifying DumpText() and 
  944.     ChangeStyle() to use "printing".
  945.  
  946. (3)    Error messages were printed even when the program worked.
  947.     They're gone.
  948.  
  949. FIXES (V0,8):
  950.  
  951.     Before recorded history.
  952.  
  953. FUTURE WORK (after V1.0):
  954.  
  955. (0)    I really don't plan to add any new features, but here are some
  956.     ideas.
  957. (1)    Allow numbering of outline headings.  This may involve using the
  958.     troff "-ms" macro package (yucch) or some serious troff work on my 
  959.     part.
  960. (2)    Get rid of StupidHack() routine.  Call New Horizons Software to see
  961.     if they will tell me their file format.
  962. (3)    Along with (2), figure out if the first 42 bytes of the Flow file
  963.     have any meaning I can use.
  964. SHAR_EOF
  965. #    End of shell archive
  966. exit 0
  967. -- 
  968. Bob Page, U of Lowell CS Dept.  page@swan.ulowell.edu  ulowell!page
  969. Have five nice days.
  970.